package cn.cloudbae.kit;


import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.Validate;

/**
 * 参考VJTools
 * @author chenc
 *
 */
public class Randomkit {
	
	/**
	 * 获取Random实例
	 * 返回无锁的ThreadLocalRandom
	 */
	public static Random threadLocalRandom() {
		return ThreadLocalRandom.current();
	}
	
	public static SecureRandom secureRandom() {
		try {
			return SecureRandom.getInstance("SHA1PRNG");
		} catch (NoSuchAlgorithmException e) {// NOSONAR
			return new SecureRandom();
		}
	}
	
	/**
	 * 返回0到Intger.MAX_VALUE的随机int，闭开区间，使用ThreadLocalRandom
	 * @return [0, Inteer.MAX_VALUE)
	 */
	public static int nextInt() {
		return nextInt(ThreadLocalRandom.current());
	}
	
	/**
	 * 返回0到Intger.MAX_VALUE的随机int，范围是闭开区间
	 * @param random 可传入SecureRandom或ThreadLocalRandom
	 * @return [0, Intger.MAX_VALUE)
	 */
	public static int nextInt(Random random) {
		int n = random.nextInt();
		if(n==Integer.MIN_VALUE) {
			n = 0;
		} else {
			n = Math.abs(n);
		}
		return n;
	}
	
	/**
	 * 返回0到max的随机int，闭开区间，使用ThreadLocalRandom
	 * @return [0, max)
	 */
	public static int nextInt(int max) {
		return nextInt(ThreadLocalRandom.current(), max);
	}
	
	/**
	 * 返回0到max的随机int，闭开区间
	 * @return [0, max)
	 */
	public static int nextInt(Random random, int max) {
		return random.nextInt(max);
	}
	
	/**
	 * 返回min到max的随机int，闭开区间，使用ThreadLocalRandom
	 * @param min
	 * @param max
	 * @return [min, max)
	 */
	public static int nextInt(int min, int max) {
		return nextInt(ThreadLocalRandom.current(), min, max);
	}
	
	/**
	 * 返回min到max的随机int，闭开区间
	 * @param random 
	 * @param min 必须大于等于0
	 * @param max
	 * @return [min, max)
	 */
	public static int nextInt(Random random, int min, int max) {
		Validate.isTrue(max >= min, "max must be bigger or equal to min");
		Validate.isTrue(min>=0, "min can not be negative");
		if(min==max) {
			return min;
		}
		return min + random.nextInt(max-min);
	}
	
	/**
	 * 返回0到Long.MAX_VALUE的随机long，闭开区间，使用ThreadLocalRandom
	 * @return [0, Long.MAX_VALUE)
	 */
	public static long nextLong() {
		return nextLong(ThreadLocalRandom.current());
	}
	
	/**
	 * 返回0到Long.MAX_VALUE的随机long，范围是闭开区间
	 * @param random 可传入SecureRandom或ThreadLocalRandom
	 * @return [0, Long.MAX_VALUE)
	 */
	public static long nextLong(Random random) {
		long n = random.nextLong();
		if(n == Long.MIN_VALUE) {
			n = 0;
		} else {
			Math.abs(n);
		}
		return n;
	}
	
	/**
	 * 返回0到max的随机int，闭开区间，使用ThreadLocalRandom
	 * @return [0, max)
	 */
	public static long nextLong(long max) {
		return nextLong(ThreadLocalRandom.current(), 0, max);
	}
	
	/**
	 * 返回0到max的随机int，闭开区间
	 * @return [0, max)
	 */
	public static long nextLong(Random random, long max) {
		return nextLong(random, 0, max);
	}
	
	/**
	 * 返回min到max的随机long，闭开区间，使用ThreadLocalRandom
	 * @param min 必须大于等于0
	 * @param max
	 * @return [min, max)
	 */
	public static long nextLong(long min, long max) {
		return nextLong(ThreadLocalRandom.current(), min, max);
	}
	
	/**
	 * 返回min到max的随机long，闭开区间
	 * @param random 
	 * @param min 必须大于等于0
	 * @param max
	 * @return [min, max)
	 */
	public static long nextLong(Random random, long min, long max) {
		Validate.isTrue(max >= min, "max must be bigger or equal to min");
		Validate.isTrue(min>=0, "min can not be negative");
		if(min==max) {
			return min;
		}
		return (long)(min+((max-min) * random.nextDouble()));
	}
	
	
	/**
	 * 返回0到DOUBLE.MAX_VALUE的随机double，闭开区间，使用ThreadLocalRandom
	 * @return [0, DOUBLE.MAX_VALUE)
	 */
	public static double nextDouble() {
		return nextDouble(ThreadLocalRandom.current(), Double.MAX_VALUE);
	}
	
	/**
	 * 返回0到DOUBLE.MAX_VALUE的随机double，闭开区间
	 * @return [0, DOUBLE.MAX_VALUE)
	 */
	public static double nextDouble(Random random) {
		return nextDouble(random, Double.MAX_VALUE);
	}
	
	/**
	 * 返回0到max的随机double，闭开区间，使用ThreadLocalRandom
	 * @return [0, max)
	 */
	public static double nextDouble(double max) {
		return nextDouble(ThreadLocalRandom.current(), max);
	}
	
	/**
	 * 返回0到max的随机double，闭开区间
	 * @return [0, max)
	 */
	public static double nextDouble(Random random, double max) {
		return nextDouble(random, 0, max);
	}
	
	/**
	 * 返回min到max的随机double，闭开区间，使用ThreadLocalRandom
	 * @return [min, max)
	 */
	public static double nextDouble(final double min, final double max) {
		return nextDouble(ThreadLocalRandom.current(), min, max);
	}
	
	/**
	 * 返回min到max的随机double，闭开区间
	 * @return [min, max)
	 */
	public static double nextDouble(Random random, final double min, final double max) {
		Validate.isTrue(max >= min, "max must be bigger or equal to min");
		Validate.isTrue(min>=0, "min can not be negative");
		if(Double.compare(min,  max)==0) {
			return min;
		} 
		return min + ((max -min) * random.nextDouble());
	}
	
	/**
	 * 随机字母或数字，固定长度，使用ThreadLocalRandom
	 */
	public static String randomStringFixLength(int length) {
		return RandomStringUtils.random(length, 0, 0, true, true, null, threadLocalRandom());
	}
	
	/**
	 * 随机字母或数字，固定长度
	 */
	public static String randomStringFixLength(Random random, int length) {
		return RandomStringUtils.random(length, 0, 0, true, true, null, random);
	}

	/**
	 * 随机字母或数字，随机长度，使用ThreadLocalRandom
	 */
	public static String randomStringRandomLength(int minLength, int maxLength) {
		return RandomStringUtils.random(nextInt(minLength, maxLength), 0, 0, true, true, null, threadLocalRandom());
	}
	
	/**
	 * 随机字母或数字，随机长度
	 */
	public static String randomStringRandomLength(Random random, int minLength, int maxLength) {
		return RandomStringUtils.random(nextInt(minLength, maxLength), 0, 0, true, true, null, random);
	}
	
	/**
	 * 随机字母，固定长度，使用ThreadLocalRandom
	 */
	public static String randomLetterFixLength(int length) {
		return RandomStringUtils.random(length, 0, 0, true, false, null, threadLocalRandom());
	}
	
	/**
	 * 随机字母，固定长度
	 */
	public static String randomLetterFixLength(Random random, int length) {
		return RandomStringUtils.random(length, 0, 0, true, false, null, random);
	}
	
	/**
	 * 随机字母，随机长度，使用ThreadLocalRandom
	 */
	public static String randomLetterRandomLength(int minLength, int maxLength) {
		return RandomStringUtils.random(nextInt(minLength, maxLength), 0, 0, true, false, null, threadLocalRandom());
	}
	
	/**
	 * 随机字母，随机长度
	 */
	public static String randomLetterRandomLength(Random random, int minLength, int maxLength) {
		return RandomStringUtils.random(nextInt(minLength, maxLength), 0, 0, true, false, null, random);
	}
	
	/**
	 * 随机数字，固定长度，使用ThreadLocalRandom
	 */
	public static String randomNumberFixLength(int length) {
		return RandomStringUtils.random(length, 0, 0, false, true, null, threadLocalRandom());
	}
	
	/**
	 * 随机数字，固定长度
	 */
	public static String randomNumberFixLength(Random random, int length) {
		return RandomStringUtils.random(length, 0, 0, false, true, null, random);
	}
	
	/**
	 * 随机数字，随机长度，使用ThreadLocalRandom
	 */
	public static String randomNumberRandomLength(int minLength, int maxLength) {
		return RandomStringUtils.random(nextInt(minLength, maxLength), 0, 0, false, true, null, threadLocalRandom());
	}
	
	/**
	 * 随机数字，随机长度
	 */
	public static String randomNumberRandomLength(Random random, int minLength, int maxLength) {
		return RandomStringUtils.random(nextInt(minLength, maxLength), 0, 0, false, true, null, random);
	}
	
	/**
	 * 随机ASCII字符(含字母，数字及其他符号)，固定长度
	 */
	public static String randomAsciiFixLength(int length) {
		return RandomStringUtils.random(length, 32, 127, false, false, null, threadLocalRandom());
	}

	/**
	 * 随机ASCII字符(含字母，数字及其他符号)，固定长度
	 */
	public static String randomAsciiFixLength(Random random, int length) {
		return RandomStringUtils.random(length, 32, 127, false, false, null, random);
	}

	/**
	 * 随机ASCII字符(含字母，数字及其他符号)，随机长度
	 */
	public static String randomAsciiRandomLength(int minLength, int maxLength) {
		return RandomStringUtils.random(nextInt(minLength, maxLength), 32, 127, false, false, null,
				threadLocalRandom());
	}

	/**
	 * 随机ASCII字符(含字母，数字及其他符号)，随机长度
	 */
	public static String randomAsciiRandomLength(Random random, int minLength, int maxLength) {
		return RandomStringUtils.random(nextInt(random, minLength, maxLength), 32, 127, false, false, null, random);
	}
	
}
